闲话 20.9.20

闲话

吓死我了我还以为joke3579的闲话永久停更了。

不知道为什么 最近这些天一直在唱《non-breath oblige》
但是没有歌词 因此很抓狂 因为原曲很快我根本记不住词
哪位好心人给一下歌词(

话说饭最近似乎停更了
然后转职成了职业画家(

这是一张画!

好看!
话说他歌的pv都是他(以及勤奋的助手们)画的
饭还在发布《若能化作彗星》后拿这首歌的pv做例子讲了一下呢
事职业画家!

有哪位好心人能和我说一下饭的近况啊(
有新歌吗(多半没有吧我猜)
有那更好了
孩子瘾犯了

一道dp题(?)

给一棵 n 个点的 AVL树,节点权值即为编号。需要把它删到剩下 k 个点。构造一种方案使得删完后的树还是 AVL 树且字典序最小。输出每个点在该方案下的存留情况。

n105,1kn

这题有 O(nlogn) 的做法但我不会。讲一下 O(nlog2n) 的。

首先贪一下,按照先序遍历枚举节点通过dp查看可达性。

具体地,设 fi,j 为在原树形态的基础上以 i 为根节点,构成一棵深度为 j 的 AVL 需要几个节点。容易写出dp方程:

fi,j=min(fls,i1+frs,i1,fls,i2+frs,i1,fls,i1+frs,i2)+1

枚举节点,将该节点与其所有祖先标记为必选,标记过程中更新标记对象父节点的dp数组。随后对根节点进行判断。如果在钦定该节点必选的情况下存在一种深度 d 使得 frt,dk,该节点就可以被选择。
因此有标记 i 节点为必选的方式:赋 fi,0,fi,1inf

若不可被选择,需要返回未选的情况。

对单个节点的判断是 O(树高2) 的。由于是 AVL 树,因此树高为 O(logn)

code
#include <bits/stdc++.h>
#define rep(i,a,b) for (register int (i) = (a); (i) <= (b); ++(i))
#define pre(i,a,b) for (register int (i) = (a); (i) >= (b); --(i))
using namespace std;
#define int long long
const int N = 5e5 + 10;
int n, k, t1, rt, u, ans, flag[N], f[N][25], g[N][25];

#ifdef ONLINE_JUDGE
    char buf[1<<21], *p1 = buf, *p2 = buf;  inline char getc() { return (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<21, stdin), p1 == p2) ? EOF : *p1++); }
    #define getchar getc
#endif
template <typename T> inline void get(T & x){
	x = 0; char ch = getchar(); bool f = false; while (ch < '0' or ch > '9') f = f or ch == '-',  ch = getchar();
	while (ch >= '0' and ch <= '9') x = (x<<1) + (x<<3) + (ch^48), ch = getchar(); f && (x = -x);
} template <typename T, typename ... Args> inline void get(T & x, Args & ... _Args) { get(x); get(_Args...); }

struct node {
    int fa, ls, rs, dp, cnt;
    #define ls(p) avl[p].ls
    #define rs(p) avl[p].rs
    #define fa(p) avl[p].fa
    #define dep(p) avl[p].dp
    #define cnt(p) avl[p].cnt
    #define isls(p) (p == ls(fa(p)))
} avl[N];

void upd(int u) {
    f[u][0] = f[u][1] = 1e9;
    for (int i = 2; i <= dep(u); i++) f[u][i] = min( f[ls(u)][i - 1] + min( f[rs(u)][i - 1] , f[rs(u)][i - 2] ) + 1 , f[ls(u)][i - 2] + f[rs(u)][i - 1] + 1 );
}

void dfs(int u) {
    if (ls(u)) dfs(ls(u));
    if (rs(u)) dfs(rs(u));
    dep(u) = max(dep(ls(u)), dep(rs(u))) + 1;
    upd(u);
    f[u][0] = 0, f[u][1] = 1;
}

bool check(int u) {
    if (flag[u]) return 1;
    flag[u] ++;
    for (int i = 0; i <= dep(u); i++) g[u][i] = f[u][i];
    f[u][0] = 1e9;
    while (u != rt) {
        u = fa(u);
        for (int i = 0; i <= dep(u); i++) g[u][i] = f[u][i];
        upd(u); flag[u] ++;
    } int mn = 1e9;
    for (int i = 1; i <= dep(rt); i++) mn = min(mn, f[rt][i]);
    return mn <= k;
}

void roll_back(int u) {
    flag[u] --;
    for (int i = 0; i <= dep(u); i++) f[u][i] = g[u][i];
    while (u != rt) {
        u = fa(u);
        for (int i = 0; i <= dep(u); i++) f[u][i] = g[u][i];
        flag[u] --;
    }
}

signed main() {
    get(n, k);
    rep(i,1,n) {
        get(t1);
        if (t1 == -1) rt = i;
        else {
            if (t1 > i) ls(t1) = i;
            else rs(t1) = i;
        } fa(i) = t1;
    } memset(f, 0x3f, sizeof f);
    rep(i,0,n) f[i][0] = 0;
    dfs(rt);
    rep(i,1,n) {
        if (check(i)) cout << 1;
        else cout << 0, roll_back(i);
    }
    return 0;
}

置换环

定义在集合 P 上的置换为一个 PP 的双射 f。容易发现,任何一个置换 f 都可以被大小为 |P| 的排列 p 表示。由置换的定义自然导出单位置换 e 与置换的复合运算。定义 fkf 自复合 k 次后得到的置换。对于置换 f,若 fk=ek(k>0) 极小,就称 kf 的周期。

对于一个 P 上的置换 f 对应的排列 p ,我们在一个 |P| 个点的图上,由 ipi 连边,会得到一个由环构成的有向图,这称作 f 的置换环图,其中的环称作 f 的一个置换环。

断言:f 的周期为所有置换环大小的最小公倍数。

证明:

f 仅有一个置换环时定理显然成立,因为每个节点都需要环大小长度的遍历后才能回到其本身。

首先考察 f 仅有两个置换环的情况。设这两个环的大小为 ab。当 a=b 时退化到一个置换环的情况,显然成立。因此考虑 ab。不妨设 a<b
我们需要的是同时遍历完两个环的最小长度。现讨论遍历两个环的过程中位置的同步度。不妨设遍历 aperiod(a,b)b 环后 a 环被遍历完。容易发现定义是良的,因为当 period(a,b)=1 时显然成立。

考虑当遍历完一个环后在另一个环上余下的长度 ba
baa,那 period(a,b)=ba。因此有

总周期=aperiod(a,b)×b=aba×b=a×bba=a×bgcd(a,b)=lcm(a,b)

考虑 baa。由于现在需要让 aba 同步,因此我们现在需要解决的子问题表述出了 period(a,b)=period(a,ab)。根据更相减损术,这表明 period(a,b)=gcd(a,b)。这也表示了 baa 是当前情况的特解。

因此当只存在两个环时有

总周期=aperiod(a,b)×b=a×bgcd(a,b)=lcm(a,b)

同时这给出了将两个大小任意的环归约成一个等价环的方法。

对于 k(k>2) 个环的情况,可以先将两个环归约为一个环,这就转化到了 k1 个环的情况。根据数学归纳法,该断言成立。

posted @   joke3579  阅读(86)  评论(4编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示